package icu.zlz.emqx.utils;

import icu.zlz.common.core.exception.ServiceException;
import icu.zlz.common.core.utils.StringUtils;

import java.util.regex.Pattern;

/**
 * @author zangsheng
 */
public class MqttTopicValidator {


    /**
     * 判断给定的MQTT主题名是否有效
     *
     * @param topic 主题名
     */
    public static void isValidMqttTopic(String topic) {
        //空主题名无效
        if (!StringUtils.hasText(topic)) {
            throw new ServiceException("主题名不能为空");
        }
        // 首先检查主题是否符合基本字符要求,没有特殊字符
        if (!Pattern.compile("^[a-zA-Z0-9][a-zA-Z0-9_#+/*]*$")
                .matcher(topic).matches()) {
            throw new ServiceException("主题名不能包含特殊字符以及不能以/或_开头");
        }
        //计数#
        int count = 0;
        for (int i = 1; i < topic.length(); i++) {

            if (topic.charAt(i) == '+' || topic.charAt(i) == '#') {
                if (topic.charAt(i - 1) != '/') {
                    throw new ServiceException("通配符必须在/后面");

                }
            }
            if (topic.charAt(i) == '#' && (++count > 1)) {
                throw new ServiceException("通配符#只能在最后");
            }

        }
        if (topic.charAt(topic.length() - 1) == '/' || (topic.charAt(topic.length() - 1) != '#' && count != 0)) {
            throw new ServiceException("不能以/结尾或且只有有一个#通配符");

        }


    }

    public static void main(String[] args) {
        String[] testTopics = {
                "a/+/a",
                "smartcity/#/+/traffic",
                "smartcity/+/traffic/",
                "smartcity/+/traffic ",
                "smartcity/+/traffic/++",
                "smartcity/+/traffic/#/#",
                "smartcity/+/traffic/#+",
                "sensors/temperature",
                "smarthome/livingroom/lights/status",
                "smartcity/#",
                "sensors/temperature/101",
                "devices/sensor_123/data",
                "#invalidStart",
                "+invalidStartToo",
                "invalid topic/with spaces",
                "sensors/temperature@with@special@chars",
                "smartcity+invalidPlacement",
                "//doubleslash",
                "invalid/topic/with/trailing/#",
                "another/invalid/topic+with+plus",
                "just/a/very/long/topic/name/example",
                "valid/+/valid",
                "valid/#"
        };

        for (String topic : testTopics) {
            isValidMqttTopic(topic);
        }
    }
}

